package com.yuanchu.store.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yuanchu.common.exception.YuanChuException;
import com.yuanchu.common.utils.R;
import com.yuanchu.store.client.FeignAuthClient;
import com.yuanchu.store.dto.AuthParamsDto;
import com.yuanchu.store.dto.WeChatSessionModel;
import com.yuanchu.store.entity.YoshopUserEntity;
import com.yuanchu.store.entity.YoshopUserOauthEntity;
import com.yuanchu.store.service.LoginService;
import com.yuanchu.store.service.YoshopUserOauthService;
import com.yuanchu.store.service.YoshopUserService;
import com.yuanchu.store.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @version: 1.0
 * @Author: adan
 * @description:
 * @date: 2024-01-28 18:32
 */
@Slf4j
@Service
public class LoginServiceImpl implements LoginService {


    private static final String APPID = "wx1fe248dc8d5b9858";
    private static final String APPSECRET = "d0852a0f67d6228425c1fad9f748a072";

    @Value("${yuanchu.security.client-id}")
    private String clientId;

    @Value("${yuanchu.security.client-secret}")
    private String clientSecret;

    @Resource
    private YoshopUserOauthService userOauthService;
    @Resource
    private YoshopUserService userService;
    // @Resource
    // private JwtUtils jwtUtils;
    @Resource
    private FeignAuthClient feignAuthClient;
    @Resource
    private RedisUtils redisUtils;

    @Override
    public Map<String, Object> login(String code, String oauth, YoshopUserEntity userInfo) {
        // 微信服务器的接口路径
        String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + APPID + "&secret=" + APPSECRET +
                "&js_code=" + code + "&grant_type=authorization_code";
        RestTemplate restTemplate = new RestTemplate();
        // 进行网络请求,访问微信服务器接口
        ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, null, String.class);
        // 根据返回值进行后续操作
        String openid = null;
        String session_key = null;
        String errcode = null;
        String errmsg = null;
        if (responseEntity.getStatusCode() == HttpStatus.OK) {
            String sessionData = responseEntity.getBody();
            // Gson gson = new Gson();
            // //将json字符串转化为实体类;
            WeChatSessionModel weChatSessionModel = JSON.parseObject(sessionData, WeChatSessionModel.class);
            // weChatSessionModel = gson.fromJson(sessionData, WeChatSessionModel.class);
            // 获取用户的唯一标识
            openid = weChatSessionModel.getOpenid();
            // 获取会话秘钥（具有时效性，用户登录的临时通行证）
            // 登录后前端的每次接口请求都需带上session_key
            session_key = weChatSessionModel.getSession_key();
            // 获取错误码
            errcode = weChatSessionModel.getErrcode();
            // 获取错误信息
            errmsg = weChatSessionModel.getErrmsg();
        }
        if (openid == null || session_key == null) {
            return R.error("errcode: " + errcode + ";errmsg: " + errmsg);
        }
        YoshopUserOauthEntity userOauth = userOauthService
                .getOne(new QueryWrapper<YoshopUserOauthEntity>().eq("oauth_id", openid));
        // 用户不存在，
        if (userOauth == null) {
            // 创建新用户
            YoshopUserEntity userEntity = saveDefaultUserUser();
            // 保存用户信息
            boolean flag = saveUserOauth(oauth, openid, userEntity);
            if (!flag) { return R.error("用户login失败！"); }
            // 生成token
            // token: "21349e485e2ef9648f2b951176ec3b17"
            // userId: 1
            return getToken(userEntity.getUserId(), userEntity.getNickName());
        }
        // 用户已存在，生成token
        YoshopUserEntity user = userService.getById(userOauth.getUserId());
        return getToken(userOauth.getUserId(), user.getNickName());
    }

    // private Map<String, Object> getToken(Integer userId) {
    //     String token = jwtUtils.generateTokenNotExpired(String.valueOf(userId));
    //     Map<String, Object> map = new HashMap<>();
    //     map.put("token", token);
    //     map.put("userId", userId);
    //     // 存入redis
    //     redisUtils.set("token_"+userId, map);
    //     return map;
    // }
    private Map<String, Object> getToken(Integer userId, String username) {
        AuthParamsDto authParam = new AuthParamsDto();
        authParam.setUserid(userId);
        authParam.setUsername(username);
        authParam.setAuthType("wxchat");

        MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
        paramsMap.set("grant_type", "password");
        paramsMap.set("username", JSON.toJSONString(authParam));
        paramsMap.set("client_id", clientId);
        paramsMap.set("client_secret", clientSecret);
        Map<String, String> accessToken = null;
        try {
            // POST {{auth_host}}/auth/oauth/token?client_id=XcWebApp&client_secret=XcWebApp&grant_type=password&
            //     username={"username":"adan","authType":"password","password":"123456"}
            accessToken = feignAuthClient.postAccessToken(paramsMap);
        } catch (Exception e) {
            log.error("获取token失败：{}", e.getMessage());
            String message = e.getMessage();
            // 找到JSON并提取错误信息开始的位置
            int jsonStart = message.lastIndexOf("[") + 1;
            int jsonEnd = message.lastIndexOf("]");
            String jsonResponse = message.substring(jsonStart, jsonEnd);
            // 使用Jackson解析JSON
            ObjectMapper objectMapper = new ObjectMapper();
            Map<String, String> errorInfo = null;
            try {
                errorInfo = objectMapper.readValue(jsonResponse, new TypeReference<Map<String, String>>() {
                });
            } catch (JsonProcessingException ex) {
                // JSON解析失败
                log.error("JSON解析失败：{}", ex.getMessage());
                throw new YuanChuException(ex.getMessage());
            }
            return R.error(org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR, errorInfo.get("error_description"));
        }
        String token = accessToken.get("access_token");
        String refresh_token = accessToken.get("refresh_token");
        // 设置 7天，s为单位
        redisUtils.set("token_"+token, refresh_token, 604800);

        Map<String, Object> map = new LinkedHashMap<>();
        map.put("token", token);
        map.put("userId", userId);
        return map;
    }


    private boolean saveUserOauth(String oauth, String openid, YoshopUserEntity userEntity) {
        YoshopUserOauthEntity userOauthEntity = new YoshopUserOauthEntity();
        userOauthEntity.setUserId(userEntity.getUserId());
        userOauthEntity.setOauthType(oauth);
        userOauthEntity.setOauthId(openid);
        userOauthEntity.setStoreId(10001);
        userOauthEntity.setCreateTime(String.valueOf(System.currentTimeMillis() / 1000));
        userOauthEntity.setUpdateTime(String.valueOf(System.currentTimeMillis() / 1000));
        // 保存登入用户信息
        return userOauthService.save(userOauthEntity);
    }

    private YoshopUserEntity saveDefaultUserUser() {
        YoshopUserEntity userEntity = new YoshopUserEntity();
        int count = userService.count();
        userEntity.setNickName("微信用户_"+count);
        userEntity.setPlatform("MP-WEIXIN");
        userEntity.setStoreId(10001);
        userEntity.setLastLoginTime(String.valueOf(System.currentTimeMillis() / 1000));
        userEntity.setCreateTime(String.valueOf(System.currentTimeMillis() / 1000));
        userEntity.setUpdateTime(String.valueOf(System.currentTimeMillis() / 1000));
        // 保存用户信息
        userService.save(userEntity);
        return userEntity;
    }
}
